package org.example.util;

/**
 * @Desc:
 * @Author: yanghongjun
 * @Date: 2024/5/10
 **/

import org.example.GirdFind.FindTest;
import org.example.Main;
import org.example.MapDrawing;
import org.example.bean.Cord;
import org.example.bean.Node;

import javax.swing.*;
import java.io.File;
import java.nio.file.Files;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AStarSearch {

    private static final int DIAGONAL_COST = 14; // 假设对角线移动的代价是14（可以根据需要调整）
    private static final int V_H_COST = 10; // 假设水平和垂直移动的代价是10（可以根据需要调整）

    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        Node start = new Node(141, 516);
        Node goal = new Node(138, 493);
        int[][] maps = new int[1200][1200];
        initMapGridBlockArray(maps);
        List<Node> path = AStarSearch.astar(maps, start, goal);
        if (path == null || path.isEmpty()) {
            System.out.println("a*寻路失败：");
        }
        System.out.println("a*寻路结束 耗时：" + (System.currentTimeMillis() - now));
        //画图
        if (path == null) {
            path = new ArrayList<>();
            path.add(start);
            path.add(goal);
        }
        List<Cord> list = new ArrayList<>(0);
        for (Node node : path) {
            list.add(new Cord(node.x, node.y));
        }
        SwingUtilities.invokeLater(() -> {
            MapDrawing gameDraw = new MapDrawing(maps, list, "ThetaStarHashUtil 寻路");
            gameDraw.setVisible(true);
        });
    }


    public static List<Node> astar(int[][] maps, Node start, Node goal) {
        PriorityQueue<Node> openList = new PriorityQueue<>(Comparator.comparingInt(node -> node.f));
        Set<Node> closedList = new HashSet<>();
        Map<Node, Node> cameFrom = new HashMap<>();
        Map<Node, Integer> gScore = new HashMap<>();
        openList.add(start);
        gScore.put(start, 0);
        start.h = heuristic(start, goal);
        start.f = start.h;
        while (!openList.isEmpty()) {
            Node current = openList.poll();
            if (current.equals(goal)) {
                System.out.println("节点size = " + openList.size());
                return reconstructPath(cameFrom, current);
            }
            closedList.add(current);
            for (Node neighbor : getNeighbors(current, maps)) {
                if (closedList.contains(neighbor) || maps[neighbor.x][neighbor.y] == 1) {
                    continue;
                }
                int tentativeGScore = gScore.getOrDefault(current, Integer.MAX_VALUE) + distBetween(current, neighbor);
                if (!gScore.containsKey(neighbor)) {
                    openList.add(neighbor);
                } else if (tentativeGScore >= gScore.get(neighbor)) {
                    continue;
                }
                cameFrom.put(neighbor, current);
                gScore.put(neighbor, tentativeGScore);
                neighbor.h = heuristic(neighbor, goal);
                neighbor.f = neighbor.h + tentativeGScore;
            }
        }
        return null; // 路径未找到
    }

    private static List<Node> reconstructPath(Map<Node, Node> cameFrom, Node current) {
        LinkedList<Node> totalPath = new LinkedList<>();
        totalPath.add(current);
        while (cameFrom.containsKey(current)) {
            current = cameFrom.get(current);
            totalPath.addFirst(current);
        }
        return totalPath;
    }

    private static int heuristic(Node a, Node b) {
        return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) * 1 ; // 曼哈顿距离
    }

    private static int distBetween(Node a, Node b) {
        int dx = Math.abs(a.x - b.x);
        int dy = Math.abs(a.y - b.y);
        if (dx > 0 && dy > 0) {
            return DIAGONAL_COST; // 对角线移动代价较高
        } else {
            return V_H_COST; // 水平或垂直移动代价
        }
    }

    private static List<Node> getNeighbors(Node node, int[][] maps) {
        List<Node> neighbors = new ArrayList<>();
        int maxX = maps.length;
        int maxY = maps[0].length;

        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) {
                    continue; // 跳过自身
                }
                int nx = node.x + dx, ny = node.y + dy;
                if (nx >= 0 && nx < maxX && ny >= 0 && ny < maxY) { // 确保坐标在地图范围内
                    neighbors.add(new Node(nx, ny));
                }
            }
        }
        return neighbors;
    }


    /**
     * 初始化格子阻挡
     *
     * @param maps
     */
    public static void initMapGridBlockArray(int[][] maps) {
        try {
            //logger.info("initMapGridBlockArray start");
            File file = new File("src/main/resources/Astar0.txt");
            List<String> list = Files.readAllLines(file.toPath());
            for (int i = 0; i < list.size(); i++) {
                String s = takeOutInvisible(list.get(i));
                char[] charArray = s.toCharArray();
                for (int j = 0; j < charArray.length; j++) {
                    char c = charArray[j];
                    if (c != '0') {
                        maps[j][i] = 1;
                    }
                }
            }
            file = new File("src/main/resources/Astar1.txt");
            list = Files.readAllLines(file.toPath());
            for (int i = 0; i < list.size(); i++) {
                String s = takeOutInvisible(list.get(i));
                char[] charArray = s.toCharArray();
                for (int j = 0; j < charArray.length; j++) {
                    char c = charArray[j];
                    if (c != '0') {
                        maps[j + 600][i] = 1;
                    }
                }
            }
            file = new File("src/main/resources/Astar2.txt");
            list = Files.readAllLines(file.toPath());
            for (int i = 0; i < list.size(); i++) {
                String s = takeOutInvisible(list.get(i));
                char[] charArray = s.toCharArray();
                for (int j = 0; j < charArray.length; j++) {
                    char c = charArray[j];
                    if (c != '0') {
                        maps[j][i + 600] = 1;
                    }
                }
            }
            file = new File("src/main/resources/Astar3.txt");
            list = Files.readAllLines(file.toPath());
            for (int i = 0; i < list.size(); i++) {
                String s = takeOutInvisible(list.get(i));
                char[] charArray = s.toCharArray();
                for (int j = 0; j < charArray.length; j++) {
                    char c = charArray[j];
                    if (c != '0') {
                        maps[j + 600][i + 600] = 1;
                    }
                }
            }
            //logger.info("initMapGridBlockArray end");
        } catch (Exception e) {
            //logger.error(e, e);
        }
    }


    /**
     * 去掉字符串中的不可见字符
     *
     * @param source
     * @return
     */
    public static String takeOutInvisible(String source) {
        if (null == source || "".equals(source)) {
            return source;
        }

        Matcher m = P1.matcher(source);
        return m.replaceAll("");
    }

    private final static Pattern P1 = Pattern.compile("\\s*|\t|\r|\n");

}
